/***************************************************************
|	File:		Player.cpp
|	Author:
|	Course:
|	Purpose:
***************************************************************/
#include "Player.h"
#include "../SGD Wrappers/SGD_AudioManager.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "../SGD Wrappers/SGD_InputManager.h"
#include "../SGD Wrappers/SGD_String.h"
#include "../SGD Wrappers/SGD_EventManager.h"
#include "../SGD Wrappers/SGD_Event.h"

#include <math.h>
#include <Windows.h>

#include "GameplayState.h"
#include "ParticleSystem.h"
#include "GrappleHook.h"
#include "ObjectManager.h"
#include "Layer.h"

#include <iostream>
#include <stdlib.h>

#include "StaticObject.h"
#include "../SGD Wrappers/SGD_String.h"
#include "../SGD Wrappers/SGD_Message.h"
#include "../SGD Wrappers/SGD_MessageManager.h"
#include "CreatePlayerDiedMessage.h"


float Slope(SGD::Point point1, SGD::Point point2)
{
	return -((point2.y - point1.y) / (point2.x - point1.x));
}

Player::Player()
{
	// Stats needed for tunning movent
	m_fMoveSpeed = 600.0f;
	m_fAccelRate = 100.0f;
	m_fJumpForce = 1100.0f;
	m_fFriction = 100.0f;
	m_fGravity = 981.0f;
	m_fDashSpeed = 400.f;
	m_fCameraOff = 200.0f;

	// Misc.
	m_fDashTimer = 0.0f;
	m_fPotionMod = 1.f;
	m_fPotionTimer = 2.0f;
	m_bIsSliding = false;
	m_bGrounded = false;
	m_HasScissors = false;
	m_bDash = false;
	m_bSlidingL = false;
	m_bPrevSlide = false;
	m_bJumped = false;
	m_bGrapActive = false;
	m_bFanDeath = false;
	m_bHasPhase = true;

	m_bCanPhase = false;
	m_bIsPhasing = false;
	m_bHasNoDeathPotion = false;
	m_bHasNoFricPotion = false;
	m_bAcidDeath = false;
	m_bHasNoFricPotion = false;
	cell = 0;
	m_fAnimationTimer = 0.f;

	m_fRespawnTimer = 1.f;
	m_vtFourCorners.resize(8);


	m_pGrapGun = new GrappleGun(this);
	m_pGrapGun->SetActive(false);
	m_Arrow = new Arrow();

	ParticleSystem ps;
	ps.Load("resource//savefiles//PlayerSliding.xml", ps, *this);
	ps.GetEmitter()->SetOffsetX((int)m_ptPosition.x);
	ps.GetEmitter()->SetOffsetY((int)m_ptPosition.y);
	SetParticle(ps);

	ParticleSystem dust;
	dust.Load("resource//savefiles//DustFromCeiling.xml", dust, *this);
	dust.GetEmitter()->SetOffsetX((int)m_ptPosition.x);
	dust.GetEmitter()->SetOffsetY((int)m_ptPosition.y);
	SetParticle(dust);

	ParticleSystem fan;
	fan.Load("resource//savefiles//FanBlood.xml", fan, *this);
	SetParticle(fan);

	ParticleSystem phase;
	phase.Load("resource//savefiles//PhaseEffect.xml", phase, *this);
	SetParticle(phase);

	m_aDeath = SGD::AudioManager::GetInstance()->LoadAudio("resource/audio/Death.wav");
	m_aStomp = SGD::AudioManager::GetInstance()->LoadAudio("resource/audio/Stomp.wav");
	ParticleSystem shocked;
	shocked.Load("resource//savefiles//Electrocuted.xml", shocked, *this);
	SetParticle(shocked);

	m_fPrevPad = 0.f;
	checks = 0;
}

Player::~Player()
{
	//for (unsigned int i = 0; i < m_prParticle->GetEmitter()->size(); i++)
	//(m_prParticle->GetEmitter())[i].GetFlyweight()->UnloadTexture();

	for (unsigned int i = 0; i < m_vtParticle.size(); i++)
	{
		m_vtParticle[i]->GetEmitter()->GetAliveVec().clear();

		while (m_vtParticle[i]->GetEmitter()->GetFlyweight()->GetRefCount() > 1)
			m_vtParticle[i]->GetEmitter()->GetFlyweight()->Release();
	}

	if (m_pGrapGun)
		m_pGrapGun->KillGrappleHook();

	delete m_pGrapGun;
	delete m_Arrow;

	SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hImage);
	SGD::AudioManager::GetInstance()->UnloadAudio(m_aDeath);
	SGD::AudioManager::GetInstance()->UnloadAudio(m_aStomp);
}

void Player::Update(float dt)
{
	// Animation
	{
		if (!m_bIsSliding)
		{
			if (m_vtVelocity.x)
			{
				m_fAnimationTimer += dt;

				if (m_fAnimationTimer > 0.1f)
				{
					cell++;

					if (cell > 3)
						cell = 0;

					m_fAnimationTimer = 0.f;
				}
			}
			else
				cell = 0;
		}

		if (!m_bGrounded && !m_bStomp && !m_bIsSliding)
			cell = 3;

		if (m_bIsSliding)
		{
			m_fAnimationTimer += dt;

			if (m_fAnimationTimer > 0.1f)
			{
				cell++;

				if (cell > 2)
					cell = 2;

				m_fAnimationTimer = 0.f;
			}
		}
	}

	if (m_bFanDeath)
		m_vtParticle[2]->Update(dt);

	if (m_bShocked)
	{
		m_vtParticle[4]->Update(dt);
		m_fPotionMod = .5f;
	}


	if (m_fPhaseTimer != 1.0f)
	{
		m_vtParticle[3]->Update(dt);
		m_fPhaseTimer -= dt;
		if (m_fPhaseTimer <= 0.0f)
		{
			m_fPhaseTimer = 1.0f;
			m_bCanPhase = false;
			m_bIsPhasing = false;
			m_vtParticle[3]->GetEmitter()->GetAliveVec().clear();
			m_vtParticle[3]->GetEmitter()->SetHasLooped(false);

		}
	}

	if (m_bIsPhasing)
	{
		m_ptPosition.x += 256;
		m_bIsPhasing = false;
		m_fPhaseTimer -= dt;
	}

	m_Arrow->Input(dt, m_szScale.width);

	if (m_fPotionMod != 1.0f || m_bHasNoDeathPotion || m_bHasNoFricPotion)
		m_fPotionTimer -= dt;

	if (m_fPotionTimer <= 0.0f)
	{
		m_fPotionMod = 1.0f;
		m_fPotionTimer = 2.0f;
		m_bHasNoDeathPotion = false;
		m_bHasNoFricPotion = false;
		m_bShocked = false;
	}

	if (!m_bAlive)
	{
		if (!SGD::AudioManager::GetInstance()->IsAudioPlaying(m_aDeath) && m_fRespawnTimer == 1.f)
			SGD::AudioManager::GetInstance()->PlayAudio(m_aDeath);
		m_fRespawnTimer -= dt;
		m_vtVelocity.x -= 1.1f*m_szScale.width;
		if (abs(m_vtVelocity.x) < 5.f)
			m_vtVelocity.x = 0.f;
	}
	if (m_fRespawnTimer < -0.1f)
	{
		m_fRespawnTimer = 1.f;
		m_bAlive = true;
	}

	if (m_fRespawnTimer < 0)
	{
		SGD::MessageManager::GetInstance()->QueueMessage(new CreatePlayerDiedMessage());
		if (m_bIsSliding)
			SlideReset();
	}

	m_ptPreviousPos.y = m_ptPosition.y;
	m_ptPreviousPos.x = m_ptPosition.x;
	//Input
	Input(dt);


	m_vtVelocity.y += m_fGravity * 3 * dt;



	if (m_vtVelocity.y > m_fGravity)
		m_vtVelocity.y = m_fGravity;

	if (m_bIsSliding)
	{
		if (abs(m_vtVelocity.x) >= 1.0f)
			m_vtVelocity.x -= 150.0f * m_szScale.width * dt;
		else
			m_vtVelocity.x = 0;
	}

	if (m_pGrapGun->GetGrappleHook() != nullptr)
	{
		if (dynamic_cast<GrappleHook*>(m_pGrapGun->GetGrappleHook())->GetHasHit())
		{
			if (!m_bGrapActive)
				GrappleHookMath();
			else
			{
				m_vtGrappleVelocity.y += m_fGravity * dt;
				m_vtVelocity = m_vtGrappleVelocity;
			}
			m_bGrapActive = true;
		}
	}
	else
		m_bGrapActive = false;

	if (m_bHasNoFricPotion)
	{
		m_vtVelocity = m_vtNoFricVelocity;
	}
	//Update Position
	m_ptPosition += m_vtVelocity *dt;

	m_ptPosition.x = (float)((int)m_ptPosition.x);
	m_ptPosition.y = (float)((int)m_ptPosition.y);


	m_Arrow->SetPosition({ m_ptPosition.x + m_szSize.width / 2 + 10, m_ptPosition.y + m_szSize.height / 2 - 32 });

	m_vtFourCorners.clear();

	SGD::Point tempPoint = SGD::Point(m_ptPosition.x + 1, m_ptPosition.y);
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.x += m_szSize.width / 2.0f - 1;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.x += m_szSize.width / 2.0f - 1;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.x++;
	tempPoint.y += m_szSize.height / 2;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.y += m_szSize.height / 2 - 1;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.x -= m_szSize.width / 2;
	tempPoint.y++;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.x -= m_szSize.width / 2;
	tempPoint.y--;
	m_vtFourCorners.push_back(tempPoint);
	tempPoint.y -= m_szSize.height / 2;
	m_vtFourCorners.push_back(tempPoint);


	float temp = m_ptPosition.y - m_ptPreviousPos.y;
	if (std::abs(temp) > 1.f)//|| (m_bIsSliding && m_fPrevVelY >= 110))
		m_bGrounded = false;
	if (temp < 0)
		m_bJumped = true;


	//Update Grapple Hook
	if (m_pGrapGun->GetGrappleHook() != nullptr)
		m_pGrapGun->Update(dt);

	if (m_bHasPhase)
	{
		SGD::Point cast = SGD::Point(m_ptPosition.x + m_szSize.width + 1, m_ptPosition.y + 64);
		SGD::Point cast2 = cast;
		cast2.x += 32;

		if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast) == 2)
		{
			m_bCanPhase = true;
		}
		else if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast2) == 2)
		{
			m_bCanPhase = true;
		}
		else
			m_bCanPhase = false;
	}

	//m_bGrounded = false;
}

void Player::Render(void)
{

	if (SGD::InputManager::GetInstance()->IsControllerConnected(0))
		m_Arrow->Render(m_szScale.width);

	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();
	SGD::Point camera;

	//draw collision rectangle
	//pGraphics->DrawRectangle(GetRect(), SGD::Color(50, 50, 50));

	if (m_bIsSliding)
	{
		if (m_szScale.width > 0.0f)
			camera = { m_ptPosition.x - GameplayState::GetInstance()->GetCamX() - 5, m_ptPosition.y - GameplayState::GetInstance()->GetCamY() - 10 };
		else
			camera = { m_ptPosition.x - GameplayState::GetInstance()->GetCamX() + 5, m_ptPosition.y - GameplayState::GetInstance()->GetCamY() - 10 };
	}
	else
	{
		if (m_szScale.width > 0.0f)
			camera = { m_ptPosition.x - GameplayState::GetInstance()->GetCamX() - 17, m_ptPosition.y - GameplayState::GetInstance()->GetCamY() - 2 };
		else
			camera = { m_ptPosition.x - GameplayState::GetInstance()->GetCamX() + 13, m_ptPosition.y - GameplayState::GetInstance()->GetCamY() - 2 };
	}
	//if facing left, offset image, else draw normally
	if (m_szScale.width < 0)
	{
		//pGraphics->DrawTexture(m_hImage, SGD::Point(camera.x + m_szSize.width, camera.y), m_fRotation, {}, {}, m_szScale);
		pGraphics->DrawTextureSection(m_hImage, SGD::Point(camera.x + m_szSize.width, camera.y), Cell(cell), m_fRotation, {}, {}, m_szScale);
	}
	else
		pGraphics->DrawTextureSection(m_hImage, camera, Cell(cell), m_fRotation, m_vtRotationOffset, {}, m_szScale);
	//pGraphics->DrawTexture(m_hImage, camera, m_fRotation, m_vtRotationOffset, {}, m_szScale);

	//pGraphics->DrawRectangle({ m_vtBottomCollision[i].x - 1, m_ptGroundCheck1.y - 1, m_ptGroundCheck1.x, m_ptGroundCheck1.y }, SGD::Color{ 255, 255, 0 });
	if (m_fPhaseTimer != 1.0f)
		m_vtParticle[3]->Render();


	//Render grapple hook particle if it is alive and well
	if (m_pGrapGun->GetGrappleHook() != nullptr)
	{
		if (m_szScale.width < 0.0f)
		{
			SGD::GraphicsManager::GetInstance()->DrawLine(SGD::Point(m_ptPosition.x - GameplayState::GetInstance()->GetCamX(),
				m_ptPosition.y - GameplayState::GetInstance()->GetCamY() + (m_szSize.height / 2)),
				SGD::Point(m_pGrapGun->GetGrappleHook()->GetPosition().x - GameplayState::GetInstance()->GetCamX(), m_pGrapGun->GetGrappleHook()->GetPosition().y -
				GameplayState::GetInstance()->GetCamY() + 16), { 75, 75, 20 });
		}
		else
		{
			SGD::GraphicsManager::GetInstance()->DrawLine(SGD::Point(m_ptPosition.x - GameplayState::GetInstance()->GetCamX() + m_szSize.width,
				m_ptPosition.y - GameplayState::GetInstance()->GetCamY() + (m_szSize.height / 2)),
				SGD::Point(m_pGrapGun->GetGrappleHook()->GetPosition().x - GameplayState::GetInstance()->GetCamX(), m_pGrapGun->GetGrappleHook()->GetPosition().y -
				GameplayState::GetInstance()->GetCamY() + 16), { 75, 75, 20 });
		}

		m_pGrapGun->GetGrappleHook()->GetParticle(0)->Render();
		m_pGrapGun->GetGrappleHook()->Render();
	}

	//SGD::OStringStream debug;
	//debug << "Vel X: " << m_vtVelocity.x << "\nVel Y : " << m_vtVelocity.y << "\nGrounded : " << m_bGrounded;

	//debug << "\nJumped: " << m_bJumped;
	//debug << "\nX =" << m_ptPosition.x;
	//debug << "\nY = " << m_ptPosition.y;
	//debug << "\nTrack Time = " << GameplayState::GetInstance()->GetTrackTimer();
	//	pGraphics->DrawString(debug.str().c_str(), { 0, 0 }, SGD::Color{ 0, 0, 255 });

	//for (int i = 0; i < 8; i++)
	//{
	//	pGraphics->DrawLine(m_vtFourCorners[i], SGD::Point(m_vtFourCorners[i].x + 1, m_vtFourCorners[i].y), SGD::Color(255, i * 30, i * 10, i * 20), 4);
	//}
	if (m_bFanDeath)
		m_vtParticle[2]->Render();

	if (m_bShocked)
		m_vtParticle[4]->Render();
}

SGD::Rectangle Player::Cell(unsigned char cell)
{
	SGD::Rectangle rec;

	rec.top = 0;
	rec.left = cell*m_szImageSize.width;
	rec.right = rec.left + m_szImageSize.width;
	rec.bottom = m_szImageSize.height;

	return rec;
}

SGD::Rectangle Player::GetRect(void) const
{
	SGD::Point point = { m_ptPosition.x, m_ptPosition.y };
	SGD::Size size;
	size.width = m_szSize.width - 5;
	size.height = m_szSize.height;

	SGD::Rectangle rect = SGD::Rectangle{ point, size };

	return rect;
}

void Player::HandleCollision(BaseObject* pOther)
{
	if (dynamic_cast<StaticObject*>(pOther) != 0)
	{
		if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::SPEEDPOTION)
		{
			if (GetRect().IsIntersecting(pOther->GetRect()))
			{
				m_fPotionMod = 2;
			}
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::NODEATHPOTION)
		{
			m_bHasNoDeathPotion = true;
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);

		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::NOFRICTIONPOTION)
		{
			m_vtNoFricVelocity = m_vtVelocity;
			m_bHasNoFricPotion = true;
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);

		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::TopLeftSlant)
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Point topRight = SGD::Point(rect.right, rect.top);
			SGD::Point bottomRight = SGD::Point(rect.right, rect.bottom);
			SGD::Point bottomLeft = SGD::Point(rect.left, rect.bottom);

			if (m_vtFourCorners[5].IsWithinRectangle(rect))
			{
				m_ptPosition.y = rect.top - m_szSize.height - 1;
				m_vtVelocity.y = -15;
				m_bStomp = false;
			}
			else if (m_vtFourCorners[4].IsWithinRectangle(rect))
			{

				if (Slope(m_vtFourCorners[4], topRight) > Slope(bottomLeft, topRight))
				{
					m_ptPosition.y = (rect.bottom - (m_ptPosition.x + m_szSize.width - rect.left - 2)) - m_szSize.height;
					m_vtVelocity.y = -15;
					m_bStomp = false;
				}
			}
			m_bGrounded = true;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::InnerTopLeftSlant)
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Rectangle collRect = rect.ComputeIntersection(GetRect());
			if (m_vtFourCorners[4].IsWithinRectangle(rect))
			{
				m_ptPosition.y -= collRect.ComputeHeight() + 1;
				m_ptPosition.x -= collRect.ComputeWidth() + 1;
				m_vtVelocity.y = -15;
				m_bStomp = false;
			}
			m_bGrounded = true;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::TopRightSlant)
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Point topLeft = SGD::Point(rect.left, rect.top);
			SGD::Point bottomRight = SGD::Point(rect.right, rect.bottom);
			SGD::Point bottomLeft = SGD::Point(rect.left, rect.bottom);

			if (m_vtFourCorners[5].IsWithinRectangle(rect))
			{
				m_ptPosition.y = rect.top - m_szSize.height;
				m_vtVelocity.y = -15;
				m_bStomp = false;
			}
			else if (m_vtFourCorners[6].IsWithinRectangle(rect))
			{

				float temp1 = Slope(m_vtFourCorners[6], bottomRight);
				float temp2 = Slope(topLeft, bottomRight);

				if (temp1 > temp2)
				{
					m_ptPosition.y = rect.bottom - (rect.right - (m_ptPosition.x)) - m_szSize.height + 2;  //(rect.top + (m_ptPosition.x - GameplayState::GetInstance()->GetCamX() - rect.left + 1)) - m_szSize.height;
					m_vtVelocity.y = -15;
					m_bStomp = false;
				}
				m_bGrounded = true;
				m_bJumped = false;
			}
			else
				m_ptPosition.y -= rect.ComputeIntersection(GetRect()).ComputeHeight();


		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::InnerTopRightSlant)
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Rectangle collRect = rect.ComputeIntersection(GetRect());
			if (m_vtFourCorners[6].IsWithinRectangle(rect))
			{
				m_ptPosition.y -= collRect.ComputeHeight() + 1;
				m_ptPosition.x += collRect.ComputeWidth() + 1;
				m_vtVelocity.y = -15;
				m_bStomp = false;
			}
		}
		else if (pOther != this && (dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::GROUND || (dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::SmashCrate) && !m_bStomp))
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Rectangle collRect = rect.ComputeIntersection(GetRect());

			if (m_vtFourCorners[5].IsWithinRectangle(rect))
			{
				m_ptPosition.y -= collRect.ComputeHeight() - 1;
				m_vtVelocity.y = -15;
				m_bGrounded = true;
				m_bJumped = false;
				m_bStomp = false;

			}
			else if (m_vtFourCorners[3].IsWithinRectangle(rect))
			{
				if (m_szScale.width > 0.0f)
					m_ptPosition.x -= collRect.ComputeWidth();
				else
					m_ptPosition.x += collRect.ComputeWidth();

				m_bDash = false;
				m_vtVelocity.x = 0;
			}
			else if (m_vtFourCorners[1].IsWithinRectangle(rect))
			{
				m_ptPosition.y += collRect.ComputeHeight();
				m_vtVelocity.y = 0;
				m_bGrounded = false;
				m_bJumped = false;
				m_bStomp = false;
			}
			else if (m_vtFourCorners[7].IsWithinRectangle(rect))
			{
				m_ptPosition.x += collRect.ComputeWidth();
				m_bDash = false;
				m_vtVelocity.x = 0;
			}
			else if (m_vtFourCorners[4].IsWithinRectangle(rect))
			{
				if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(m_vtFourCorners[3]))
				{
					m_ptPosition.x -= collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(m_vtFourCorners[5]))
				{
					m_ptPosition.y -= collRect.ComputeHeight() - 1;
					m_vtVelocity.y = -15;
					m_bGrounded = true;
					m_bJumped = false;
					m_bStomp = false;
				}
				else if (collRect.ComputeWidth() < collRect.ComputeHeight())
				{
					m_ptPosition.x -= collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else
				{
					m_ptPosition.y -= collRect.ComputeHeight();
					m_vtVelocity.y = -15;
					m_bGrounded = true;
					m_bJumped = false;
					m_bStomp = false;
				}

			}
			else if (m_vtFourCorners[6].IsWithinRectangle(rect))
			{

				if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(m_vtFourCorners[7]))
				{
					m_ptPosition.x += collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else if(GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(m_vtFourCorners[5]))
				{
					m_ptPosition.y -= collRect.ComputeHeight() - 1;
					m_vtVelocity.y = -15;
					m_bGrounded = true;
					m_bJumped = false;
					m_bStomp = false;
				}
				else if (collRect.ComputeWidth() < collRect.ComputeHeight())
				{
					m_ptPosition.x += collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else
				{
					m_ptPosition.y -= collRect.ComputeHeight();
					m_vtVelocity.y = 0;
					m_bGrounded = true;
					m_bJumped = false;
					m_bStomp = false;
				}
			}
			else if (m_vtFourCorners[0].IsWithinRectangle(rect))
			{
				if (collRect.ComputeWidth() < collRect.ComputeHeight())
				{
					m_ptPosition.x += collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else
				{
					m_ptPosition.y += collRect.ComputeHeight();
					m_vtVelocity.y = 0;
					m_bStomp = false;
				}
			}
			else if (m_vtFourCorners[2].IsWithinRectangle(rect))
			{
				if (collRect.ComputeWidth() < collRect.ComputeHeight())
				{
					m_ptPosition.x -= collRect.ComputeWidth();
					m_bDash = false;
					m_vtVelocity.x = 0;
				}
				else
				{
					m_ptPosition.y += collRect.ComputeHeight();
					m_vtVelocity.y = 0;
					m_bStomp = false;
				}
			}
			else
			{
				if (GetRect().left < rect.right)
					m_ptPosition.x += collRect.ComputeWidth();
				if (GetRect().right > rect.left)
					m_ptPosition.x -= collRect.ComputeWidth();
				if (GetRect().top < rect.bottom)
					m_ptPosition.y += collRect.ComputeHeight();
				if (GetRect().bottom > rect.top)
					m_ptPosition.y -= collRect.ComputeHeight();
			}
		}
		if (m_bStomp == true && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::SmashCrate)
		{
			pOther->SetAlive(false);
			dynamic_cast<StaticObject*>(pOther)->SetWasTriggered(true);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::PhaseWall)
		{
			SGD::Rectangle rect = dynamic_cast<StaticObject*>(pOther)->GetRect();
			SGD::Rectangle collRect = rect.ComputeIntersection(GetRect());
			if (m_vtFourCorners[3].IsWithinRectangle(rect) ||
				m_vtFourCorners[2].IsWithinRectangle(rect) ||
				m_vtFourCorners[5].IsWithinRectangle(rect))
				m_ptPosition.x -= collRect.ComputeWidth();
			else
				m_ptPosition.x += collRect.ComputeWidth();

			m_bCanPhase = true;
			m_vtVelocity.x = 0;

		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::PhaseGun)
		{
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);
			checks = checks | (1 << PHASE);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::GRAPPLEHOOK)
		{
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);
			m_pGrapGun->SetAlive(false);
			checks = checks | (1 << GRAPPLE);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Fan)
		{
			if (!m_bHasNoDeathPotion)
				SetAlive(false);
			m_bFanDeath = true;
			m_vtVelocity.x = 0;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::GravBoots)
		{
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);
			checks = checks | (1 << BOOTS);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Scissors)
		{
			pOther->SetAlive(false);
			GameplayState::GetInstance()->GetObjectManager()->AddObjectTable(pOther, 0);
			checks = checks | (1 << SCISSORS);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Win)
		{
			if (checks & (1 << SCISSORS))
				GameplayState::GetInstance()->SetVictory(true);
			//pGame->SetVictory(true);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Smashable)
		{
			/*
				   When the player is currently stomping, it should destroy the object tagged with "Smashable" and
				   ALL objects next to it that have the same tag. So if the player smashes a "Smashable" box, the
				   entire box should break. Same with the "Smashable" floor. Somehow it has to check all the objects
				   next to it to see if they have the same tag. Then if one tile tagged "Smashable" is destroyed, it should
				   destroy all the tiles (with the same "Smashable" tag) touching the inital tile that was destroyed.



				   Or, A single tile could be tagged with "Smashable" and at that location the system, would place
				   the proper object at that location as its own individual object so that we don't check for other tiles
				   and just delete that placed object


				   */

		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::LandMine)
		{
			if (!m_bHasNoDeathPotion)
				SetAlive(false);
			m_vtVelocity.x = 0;
			pOther->SetAlive(false);
			dynamic_cast<StaticObject*>(pOther)->SetWasTriggered(true);
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::AcidPool)
		{
			if (!m_bHasNoDeathPotion)
				SetAlive(false);
			m_vtVelocity.x = 0;
			m_bAcidDeath = true;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Jet)
		{
			SetAlive(false);
			m_bAcidDeath = true;
		}

		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::TeslaCoil)
		{
			m_bShocked = true;
			m_fPotionTimer = 1.9f;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Wire)
		{
			m_bShocked = true;
			m_fPotionTimer = 1.9f;
		}
		else if (pOther != this && dynamic_cast<StaticObject*>(pOther)->GetObjectType() == ObjectType::Hookable)
		{
			//if (m_pGrapGun != nullptr)
			//if (m_pGrapGun->GetGrappleHook() != nullptr)
			//	m_vtVelocity = m_vtGrappleVelocity;

			m_pGrapGun->KillGrappleHook();
		}
	}

}

void Player::Input(float dt)
{

	SGD::InputManager* input = SGD::InputManager::GetInstance();
	SGD::Vector controller;
	controller = input->GetLeftJoystick(0);

	//input->Update();
	if (m_bAlive)
	{

		//Basic_Movement
#pragma region Basic_Movement

		if (!m_bIsSliding)
		{
			//movement left or right
			if ((input->IsKeyDown(SGD::Key::D) == true
				|| controller.x > 0.8f)
				&& !input->IsKeyDown(SGD::Key::A))
			{
				if (m_vtVelocity.x < 0)
					m_vtVelocity.x = 0;

				Accel();

				// scale 1 if going right
				if (m_szScale.width < 0)
					m_szScale.width *= -1;
			}

			if ((input->IsKeyDown(SGD::Key::A) == true
				|| controller.x < -0.8f)
				&& !input->IsKeyDown(SGD::Key::D))
			{

				if (m_vtVelocity.x > 0)
					m_vtVelocity.x = 0;

				Accel();

				//scale -1 if going left
				if (m_szScale.width > 0)
					m_szScale.width *= -1;

			}


			if (input->IsKeyUp(SGD::Key::A) && input->IsKeyUp(SGD::Key::D)
				&& abs(controller.x) < .1f && m_bGrounded)
			{
				//set x vel to 0 (stop)
				m_vtVelocity = { 0, m_vtVelocity.y };

				//if (m_vtVelocity.x < 0.001f * m_szScale.width)
				//{
				//	m_vtVelocity.x = 0;
				//}

				//if friction apply friction
				//if (m_fFriction > 0.01f )
				//{
				//	m_fFriction -= 0.01f;
				//}
				//else if (m_fFriction <= 0.1f )
				//	m_fFriction = 0;
			}
			else if ((input->IsKeyReleased(SGD::Key::A) || input->IsKeyReleased(SGD::Key::D))
				|| (abs(controller.x) < abs(m_fPrevPad)))
			{

				m_vtVelocity = { 0, m_vtVelocity.y };
			}


		}
		//if grounded, then add jump speed
		if ((input->IsKeyDown(SGD::Key::W) == true
			|| input->IsKeyDown(SGD::Key::Space) == true
			//|| controller.y < -0.5f
			|| input->IsButtonDown(0, 0))
			&& m_bGrounded == true)
		{
			if (m_bIsSliding)
			{
				SGD::Point cast = SGD::Point(m_ptPosition.x, m_ptPosition.y - 63);
				SGD::Point cast2 = SGD::Point(m_ptPosition.x, m_ptPosition.y - 31);
				SGD::Point cast3 = SGD::Point(m_ptPosition.x + m_szSize.width, m_ptPosition.y - 63);
				SGD::Point cast4 = SGD::Point(m_ptPosition.x + m_szSize.width, m_ptPosition.y - 31);

				if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast))
				{
					//Do Nothing
				}
				else if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast2))
				{
					//Do Nothing
				}
				else if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast3))
				{
					//Do Nothing
				}
				else if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast4))
				{
					//Do Nothing
				}
				else
				{
					m_vtVelocity = { m_vtVelocity.x, -m_fJumpForce };
					m_bGrounded = false;
					m_bJumped = false;

					//reset sliding if sliding
					if (m_bIsSliding)
						SlideReset();
				}
			}
			else
			{
				m_vtVelocity = { m_vtVelocity.x, -m_fJumpForce };
				m_bGrounded = false;
				m_bJumped = false;

				//reset sliding if sliding
				if (m_bIsSliding)
					SlideReset();
			}
		}

#pragma endregion

		//Dash
#pragma region Dash

		//If not Dashing, then dash
		if (input->IsKeyPressed(SGD::Key::LeftShift) == true
			|| input->IsButtonPressed(0, 1)
			)
		{
			if (m_bCanPhase && !m_bIsPhasing && m_fPhaseTimer == 1.0f)
			{
				m_bIsPhasing = true;
				m_fPhaseTimer -= .001f;
			}
			else if (!m_bDash)
				m_bDash = true;
		}

		if (m_bDash)
			Dash(dt);

#pragma endregion

		//Slide
#pragma region Slide

		Slide();

#pragma endregion

		//Stomp
#pragma region Stomp

		//Dont stomp if previously sliding and haven't released S
		if (input->IsKeyReleased(SGD::Key::S) == true
			|| input->IsButtonReleased(0, 3))
			m_bPrevSlide = false;

		//if(input->IsButtonReleased(0, 3) && (checks&(1<<BUTTON3)))
		//m_bPrevSlide = false;
		//only stomp if you didn't just previously werent sliding, and not grounded
		if ((input->IsKeyPressed(SGD::Key::S) == true
			|| input->IsButtonPressed(0, 3))
			&& m_bJumped
			&& !m_bGrounded
			&& !m_bPrevSlide
			&& (checks & (1 << BOOTS)))
			m_bStomp = true;

		if (m_bStomp)
			Stomp();

#pragma endregion

#pragma region Fire Grapple Hook
		if (input->IsKeyPressed(SGD::Key::MouseLeft)
			|| input->IsButtonPressed(0, 2))
		{
			//if (m_pGrapGun->GetAlive() == false)
			//checks = 1;
			if (checks & (1 << GRAPPLE) && m_pGrapGun != nullptr && m_pGrapGun->GetGrappleHook() == nullptr)
				m_pGrapGun->Fire();
		}

#pragma endregion
	}

	m_fPrevPad = controller.x;
}


//Helper Funcstions

void Player::Accel()
{
	//Add vel.x* direction * potion modifier to previous vel.x
	//vel.y remains unchanged, add gravity as usual
	if (m_vtVelocity.x < m_fMoveSpeed* m_fPotionMod)
	{
		m_vtVelocity = { (m_szScale.width * m_fAccelRate) + m_vtVelocity.x, m_vtVelocity.y };

		//if vel.x is >= to max speed then cap at max speed
		if (std::abs(m_vtVelocity.x) >= m_fMoveSpeed* m_fPotionMod)
			m_vtVelocity = { m_szScale.width * m_fMoveSpeed * m_fPotionMod, m_vtVelocity.y };
	}
	else if (m_bGrounded)
		m_vtVelocity.x -= 10;
}

void Player::Dash(float dt)
{
	//Dash Timer
	m_fDashTimer += dt;

	//added so that player can't abuse Dash
	if (m_fDashTimer >= 1.f)
	{
		m_fDashTimer = 0.f;
		m_bDash = false;
	}

	if (m_szScale.width > 0.0f)
	{
		SGD::Point cast = SGD::Point(m_ptPosition.x + m_szSize.width + 3, m_ptPosition.y + 64);
		if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast))
		{
			return;
		}
	}
	else if (m_szScale.width < 0.0f)
	{
		SGD::Point cast = SGD::Point(m_ptPosition.x - 3, m_ptPosition.y + 64);
		if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast))
		{
			return;
		}
	}


	//dash for 0.4s in the direction you are facing
	if (m_fDashTimer < 0.4f && m_bDash)
		m_vtVelocity.x = m_szScale.width * m_fDashSpeed * 3;

}

void Player::Slide()
{
	SGD::InputManager* input = SGD::InputManager::GetInstance();


	if (m_bIsSliding)
	{
		SGD::Point cast = SGD::Point(m_ptPosition.x, m_ptPosition.y - 64);
		if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast))
		{
			m_bIsSliding = true;
			if (!m_bSlidingL)
				m_vtVelocity.x = 500;
			else
			{
				m_bSlidingL = true;
				m_vtVelocity.x = -500;
			}
			return;

		}

		cast.x += m_szSize.width - 10;
		if (GameplayState::GetInstance()->GetObjectManager()->CheckPointInCollision(cast))
		{
			m_bIsSliding = true;
			if (!m_bSlidingL)
				m_vtVelocity.x = 500;
			else
			{
				m_bSlidingL = true;
				m_vtVelocity.x = -500;
			}
			return;
		}
	}

	//If not pressing S and currently sliding, then reset rotation, collision box, etc
	if (input->IsControllerConnected(0))
	{

		if ((input->IsButtonUp(0, 3)
			&& input->IsKeyUp(SGD::Key::S))
			&& m_bIsSliding)
			SlideReset();
	}
	else
	{
		if (input->IsKeyUp(SGD::Key::S) == true
			&& m_bIsSliding)
			SlideReset();
	}

	if ((input->IsKeyDown(SGD::Key::S) == true
		|| input->IsButtonDown(0, 3))
		&& !m_bIsSliding
		&& m_bGrounded
		&& !m_bStomp)
	{
		m_bIsSliding = true;
		if (m_vtVelocity.x < 0.0f)
			m_bSlidingL = true;
		else
			m_bSlidingL = false;

		cell = 0;
		SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hImage);

		SetImage(SGD::GraphicsManager::GetInstance()->LoadTexture(L"resource/graphics/ScientistSlide.png"));
		SetSize({ 128, 64 });
		SetImageSize({ 138, 87 });
		m_ptPosition.y += 64;
		if (m_szScale.width == 1)
			m_ptPosition.x -= m_szSize.width / 2;
		m_fAnimationTimer = 0.0f;
	}
}

void Player::SlideReset()
{
	//resets rotation. Scaling also if facing left
	m_bIsSliding = false;
	m_bPrevSlide = true;

	SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hImage);
	SetImage(SGD::GraphicsManager::GetInstance()->LoadTexture(L"resource/graphics/ScientistRunning.png"));
	SetSize({ 64, 128 });
	SetImageSize({ 90, 136 });
	m_ptPosition.y -= 64;

	if (m_szScale.width == 1)
		m_ptPosition.x += m_szSize.width / 2 + 32;
}

void Player::Stomp()
{
	SGD::InputManager* input = SGD::InputManager::GetInstance();

	if (input->IsControllerConnected(0))
	{

		if (m_bGrounded
			&& (input->IsKeyUp(SGD::Key::S)
			&& input->IsButtonUp(0, 3)))
		{
			m_bStomp = false;
			SGD::AudioManager::GetInstance()->PlayAudio(m_aStomp);
			return;
		}
	}
	else
	{
		if (m_bGrounded
			&& input->IsKeyUp(SGD::Key::S))
		{
			m_bStomp = false;
			SGD::AudioManager::GetInstance()->PlayAudio(m_aStomp);
			return;
		}
	}


	m_vtVelocity = SGD::Vector(0.f, m_fMoveSpeed * 3);
}

void Player::GrappleHookMath()
{
	SGD::Vector hookPos;
	hookPos.x = m_pGrapGun->GetGrappleHook()->GetPosition().x;
	hookPos.y = m_pGrapGun->GetGrappleHook()->GetPosition().y;

	SGD::Vector playerPos;
	playerPos.x = m_ptPosition.x;
	playerPos.y = m_ptPosition.y;

	if (!m_bGrapActive)
	{
		m_vtGrappleVelocity = hookPos - playerPos;
		m_vtGrappleVelocity.Normalize();
		m_vtGrappleVelocity *= 2000;
		SetVelocity(m_vtGrappleVelocity);
		m_bGrounded = false;
	}
	else
	{
		m_bGrapActive = false;
		m_pGrapGun->KillGrappleHook();
	}

}

void Player::Reset()
{
	if (m_pGrapGun != nullptr)
	{
		if (m_pGrapGun->GetGrappleHook() != nullptr)
		{
			dynamic_cast<GrappleHook*>(m_pGrapGun->GetGrappleHook())->ReleaseAll();
			dynamic_cast<GrappleGun*>(m_pGrapGun)->KillGrappleHook();

		}

		m_pGrapGun->Release();
	}


	for (unsigned int i = 0; i < m_vtParticle.size(); i++)
	{
		m_vtParticle[i]->GetEmitter()->GetAliveVec().clear();

		while (m_vtParticle[i]->GetEmitter()->GetFlyweight()->GetRefCount() > 1)
			m_vtParticle[i]->GetEmitter()->GetFlyweight()->Release();
	}

	for (unsigned int i = 0; i < m_vtParticle.size(); i++)
	{
		delete m_vtParticle[i];
	}

	m_vtParticle.clear();

	m_pGrapGun = new GrappleGun(this);
	m_pGrapGun->SetAlive(false);

	ParticleSystem ps;
	ps.Load("resource//savefiles//PlayerSliding.xml", ps, *this);
	ps.GetEmitter()->SetOffsetX((int)m_ptPosition.x);
	ps.GetEmitter()->SetOffsetY((int)m_ptPosition.y);
	SetParticle(ps);

	ParticleSystem dust;
	dust.Load("resource//savefiles//DustFromCeiling.xml", dust, *this);
	dust.GetEmitter()->SetOffsetX((int)m_ptPosition.x);
	dust.GetEmitter()->SetOffsetY((int)m_ptPosition.y);
	SetParticle(dust);

	ParticleSystem fan;
	fan.Load("resource//savefiles//FanBlood.xml", fan, *this);
	SetParticle(fan);

	ParticleSystem phase;
	phase.Load("resource//savefiles//PhaseEffect.xml", phase, *this);
	SetParticle(phase);

	ParticleSystem shocked;
	shocked.Load("resource//savefiles//Electrocuted.xml", shocked, *this);
	SetParticle(shocked);

	// Stats needed for tunning movent
	m_fMoveSpeed = 600.0f;
	m_fAccelRate = 400.0f;
	m_fJumpForce = 1100.0f;
	m_fFriction = 100.0f;
	m_fGravity = 981.0f;
	m_fDashSpeed = 400.f;
	m_vtVelocity = { 0, 0 };

	// Misc.
	m_fDashTimer = 0.0f;
	m_fPotionMod = 1.f;
	m_fPotionTimer = 2.0f;
	m_bIsSliding = false;
	m_bGrounded = false;
	m_HasScissors = false;
	m_bDash = false;
	m_bShocked = false;
	m_bSlidingL = false;
	m_bPrevSlide = false;
	m_bJumped = false;
	m_bGrapActive = false;
	m_bFanDeath = false;
	m_bHasPhase = true;
	m_bCanPhase = false;
	m_bIsPhasing = false;
	m_bHasNoDeathPotion = false;
	m_bHasNoFricPotion = false;
	m_bAcidDeath = false;
	m_bHasNoFricPotion = false;

}